package com.itmck.control;

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowItem;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 *
 * 除了在Sentinel控制台中配置各种规则之外，Sentinel还支持在代码中配置这些规则
 * 添加Sentinel规则
 *
 * @author 01
 * @date 2019-07-31
 **/
@Slf4j
@RestController
public class SentinelRuleController {

    /**
     * 测试添加流控规则
     */
    @PostMapping("/test-add-flow-rule")
    public String testAddFlowRile(String resourceName) {
        log.info("add flow rule. resourceName is {}", resourceName);
        addFlowQpsRule(resourceName);

        return "add flow rule success!";
    }

    /**
     * 添加流控规则
     *
     * @param resourceName 资源名称
     */
    private void addFlowQpsRule(String resourceName) {
        // 规则列表
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule(resourceName);
        // 针对来源
        rule.setLimitApp("default");
        // 设置阈值类型为QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 单机阈值
        rule.setCount(20);
        // 将规则添加到规则列表
        rules.add(rule);
        // 加载规则列表
        FlowRuleManager.loadRules(rules);
    }

    /**
     * 添加降级规则
     *
     * @param resourceName 资源名称
     */
    private void addDegradeRule(String resourceName) {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule(resourceName);
        // 设置降级策略为 RT
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        // set threshold RT, 10 ms（设置RT时间阈值）
        rule.setCount(10);
        // 时间窗口
        rule.setTimeWindow(10);
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }

    /**
     * 添加热点规则
     *
     * @param resourceName 资源名称
     */
    private void addHotRule(String resourceName) {
        ParamFlowRule rule = new ParamFlowRule(resourceName);
        // 参数索引
        rule.setParamIdx(0);
        // 单机阈值
        rule.setCount(5);

        // 添加参数例外项
        ParamFlowItem item = new ParamFlowItem();
        // 参数类型
        item.setClassType(int.class.getName());
        // 参数值
        item.setObject("5");
        // 限流阈值
        item.setCount(10);
        rule.setParamFlowItemList(Collections.singletonList(item));

        ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
    }

    /**
     * 添加系统规则
     */
    private void addSystemRule() {
        List<SystemRule> rules = new ArrayList<>();
        SystemRule rule = new SystemRule();
        // 设置系统最高负载阈值
        rule.setHighestSystemLoad(10);
        rules.add(rule);
        SystemRuleManager.loadRules(rules);
    }

    /**
     * 添加授权规则
     *
     * @param resourceName 资源名称
     * @param limitApp     流控应用（指调用方，多个调用方名称使用英文逗号分隔）
     */
    private void addAuthorityRule(String resourceName, String limitApp) {
        AuthorityRule rule = new AuthorityRule();
        // 资源名称
        rule.setResource(resourceName);
        // 流控应用
        rule.setLimitApp(limitApp);
        // 设置授权类型为白名单
        rule.setStrategy(RuleConstant.AUTHORITY_WHITE);

        AuthorityRuleManager.loadRules(Collections.singletonList(rule));
    }
}